package net.mingsoft.dashboard.biz.impl;

import lombok.extern.slf4j.Slf4j;
import net.mingsoft.basic.core.SessionContext;
import net.mingsoft.basic.util.HttpRequest;
import net.mingsoft.dashboard.action.q.contact.MyEmailQuery;
import net.mingsoft.dashboard.action.q.contact.MyPhoneQuery;
import net.mingsoft.dashboard.action.q.contact.SendCodeQuery;
import net.mingsoft.dashboard.action.r.MyContactDetailResponse;
import net.mingsoft.dashboard.biz.MyContactBiz;
import net.mingsoft.dashboard.cache.CodeCache;
import net.mingsoft.dashboard.dao.ContactDao;
import net.mingsoft.dashboard.enums.SendTypeEnum;
import net.mingsoft.dashboard.util.MsgCodeUtil;
import net.mingsoft.people.entity.PeopleEntity;
import net.mingsoft.zwy.biz.MessageSendBiz;
import net.mingsoft.zwy.biz.q.EmailQuery;
import net.mingsoft.zwy.biz.q.MsgQuery;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.slf4j.helpers.MessageFormatter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.Cache;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import javax.annotation.Resource;
import java.util.Date;
import java.util.Objects;

/**
 * @author gengfa
 * @date 22/03/05
 */
@Service
@Slf4j
public class MyContactBizImpl implements MyContactBiz {

    @Value("${zwy.sms.mock.enabled:false}")
    private boolean smsMock;

    @Value("${zwy.sms.mock.we-chat-bot:localhost}")
    private String weChatBotUrl;

    private static final String MOCK_TEMPLATE = "用户{} 绑定{} 收到验证码 {}";
    private static final String MSG_TEMPLATE = "【海南智库信息平台】您正在绑定{}, 验证码为: {}, 如果不是您的操作，请忽略";

    private static final String BIND_MOBILE = "手机号";
    private static final String BIND_EMAIL = "邮箱";

    @Resource
    MessageSendBiz sendBiz;

    @Resource
    ContactDao contactDao;

    @Resource
    ConcurrentMapCacheManager cacheManager;

    @Value("${zwy.sms.code-length:6}")
    private int codeLength;

    @Value("${zwy.sms.send-next:30000}")
    private int expiredPeriod;

    private static final String DEFAULT_CACHE_NAME = "sendCode";

    @Override
    public MyContactDetailResponse getMyDetail() {
        return contactDao.selectByManagerId(SessionContext.session().getIntegerId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean bindEmail(MyEmailQuery query) {
        CodeCache codeCache = (CodeCache) Objects.requireNonNull(
                Objects.requireNonNull(
                        cacheManager.getCache(DEFAULT_CACHE_NAME)).get(query.getEmail())).get();

        if (codeCache != null && StringUtils.equals(codeCache.getCode(), query.getCode())) {
            return 1 == contactDao.updateEmailById(SessionContext.session().getIntegerId(), query.getEmail());
        }
        return false;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean bindMobile(MyPhoneQuery query) {
        CodeCache codeCache = (CodeCache) Objects.requireNonNull(
                Objects.requireNonNull(
                        cacheManager.getCache(DEFAULT_CACHE_NAME)).get(query.getMobile())).get();

        try {
            if (codeCache != null && StringUtils.equals(codeCache.getCode(), query.getCode())) {
                int peopleId = contactDao.selectPeopleId(SessionContext.session().getIntegerId());
                if (peopleId <= 0) {
                    PeopleEntity entity = new PeopleEntity();
                    entity.setPeopleDateTime(new Date());
                    if (1 == contactDao.insertPeople(entity)) {
                        if (1 == contactDao.updateManager(SessionContext.session().getIntegerId(), entity.getIntegerId())) {
                            peopleId = entity.getIntegerId();
                        } else {
                            throw new Exception("update manager failed");
                        }
                    }
                }
                return peopleId > 0 && 1 == contactDao.updateMobileById(SessionContext.session().getIntegerId(), query.getMobile());
            }
        } catch (Exception e) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            log.error(e.getMessage());
        }

        return false;
    }

    @Override
    public boolean sendCode(SendCodeQuery query) {

        Cache cache = cacheManager.getCache(DEFAULT_CACHE_NAME);

        if (cache != null ) {
            Cache.ValueWrapper valueWrapper = cache.get(query.getReceiver());
            if (valueWrapper != null) {
                CodeCache extCodeCache = (CodeCache) valueWrapper.get();
                if (extCodeCache != null && (DateTime.now().getMillis() - extCodeCache.getTime()) <= expiredPeriod) {
                    return false;
                }
            }
        }

        String code = MsgCodeUtil.randomCode(codeLength);
        if (smsMock) {
            Object o = HttpRequest.sendBotMsg(weChatBotUrl, MessageFormatter.arrayFormat(MOCK_TEMPLATE, new String[]{
                    SessionContext.session().getManagerName(), query.getReceiver(), code}).getMessage());
            log.info("bot msg > {}", o);
        }

        log.info("sendCode {} {}:", query.getReceiver(), code);

        CodeCache codeCache = new CodeCache().setCode(code).setTime(new DateTime().getMillis());

        // cached
        Objects.requireNonNull(cacheManager.getCache(DEFAULT_CACHE_NAME)).put(query.getReceiver(), codeCache);

        if (!smsMock) {
            String content;
            if (SendTypeEnum.isEmail(query.getType())) {
                content = MessageFormatter.arrayFormat(MSG_TEMPLATE, new String[]{BIND_EMAIL, code}).getMessage();
                sendBiz.sendEmail(new EmailQuery().setTo(query.getReceiver()).setContent(content));
                return true;
            } else if (SendTypeEnum.isSms(query.getType())) {
                content = MessageFormatter.arrayFormat(MSG_TEMPLATE, new String[]{BIND_MOBILE, code}).getMessage();
                sendBiz.sendMsg(new MsgQuery().setMobiles(query.getReceiver()).setContent(content));
                return true;
            }
        }
        return false;
    }
}
